﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using ExpressionEvaluator.Extended;

namespace ExpressionEvaluator.BuilderTreeNode
{
	/// <summary>
	/// Internal class to store internal tree for generating expression tree.
	/// </summary>
	internal class BuilderTree
	{

        private int _AnonymousTypesCount;
		/// <summary>
		/// Initializes a new instance of the <see cref="BuilderTree"/> class.
		/// </summary>
		/// <param name="lookupNamespaces">The lookup namespaces.</param>
		/// <param name="lookupAssemblies">The lookup assemblies.</param>
		/// <param name="parameters">The parameters.</param>
		public BuilderTree(List<string> lookupNamespaces, List<string> lookupAssemblies, List<ExtensionInfo> extensions, ParameterExpression[] parameters)
		{
            _AnonymousTypesCount = 0;
			Root = new ExpressionNode();
			Current = Root;
			Parameters = parameters;
			LookupAssemblies = lookupAssemblies;
			LookupNamespaces = lookupNamespaces;
			Extensions = extensions;
		}

        /// <summary>
        /// Gets the new name of the anonymous type.
        /// </summary>
        /// <returns>Unique anonymous type name for this builder tree.</returns>
        public string GetNewAnonymousTypeName(int numberOfParameters)
        {
            return string.Format("<>f__AnonymousType{0}`{1}", _AnonymousTypesCount++, numberOfParameters);
        }

		/// <summary>
		/// Gets the parameters.
		/// </summary>
		/// <value>The parameters.</value>
		public ParameterExpression[] Parameters
		{
			get;
			private set;
		}

		/// <summary>
		/// Gets the lookup namespace patterns.
		/// </summary>
		/// <value>The lookup namespace patterns.</value>
		public List<string> LookupNamespaces
		{
			get;
			private set;
		}

		/// <summary>
		/// Gets the lookup assemblies.
		/// </summary>
		/// <value>The lookup assemblies.</value>
		public List<string> LookupAssemblies
		{
			get;
			private set;
		}

		/// <summary>
		/// Gets or sets the extensions lookups info.
		/// </summary>
		/// <value>The extensions.</value>
		public List<ExtensionInfo> Extensions
		{
			get;
			private set;
		}

		/// <summary>
		/// Gets the root node.
		/// </summary>
		/// <value>The root node.</value>
		public BuilderTreeNodeBase Root
		{
			get;
			internal set;
		}

		/// <summary>
		/// Gets the current node in tree structure.
		/// </summary>
		/// <value>The current node in tree structure.</value>
		public BuilderTreeNodeBase Current
		{
			get;
			internal set;
		}

		/// <summary>
		/// Adds the new node and set to current.
		/// </summary>
		/// <param name="newChild">The new child node.</param>
		public void AddNewAndSetToCurrent(BuilderTreeNodeBase newChild)
		{
			newChild.Parent = Current;
			if (Current != null)
			{
				Current.Nodes.Add(newChild);
			}
			Current = newChild;
			CorrectRoot();
		}

		/// <summary>
		/// Sets as parent to current node.
		/// </summary>
		/// <remarks>
		/// Replaces parent of current node with new child and moves current node from parent childs to new child childs.
		/// </remarks>
		/// <param name="newChild">The new child node.</param>
		public void SetAsParentToCurrent(BuilderTreeNodeBase newChild)
		{
			newChild.Parent = Current.Parent;
			newChild.Nodes.Add(Current);
			if (Current.Parent != null)
			{
				Current.Parent.Nodes.Remove(Current);
				Current.Parent.Nodes.Add(newChild);
			}
			Current.Parent = newChild;
			Current = newChild;
			CorrectRoot();
		}

		/// <summary>
		/// Corrects the root.
		/// </summary>
		/// <remarks>
		/// Checks if root node is topmost node in tree structure.
		/// </remarks>
		private void CorrectRoot()
		{
			if (Current.Parent == null)
			{
				Root = Current;
			}
		}

		/// <summary>
		/// Goes back to parent.
		/// </summary>
		public void GoToParent()
		{
			System.Diagnostics.Debug.Assert(Current != Root, "Whoaaa, you are already on the top!");
			Current = Current.Parent;
		}

		/// <summary>
		/// Goes back to parent expression.
		/// </summary>
		public void GoToParentExpression()
		{
			System.Diagnostics.Debug.Assert(Current != Root, "Whoaaa, you are already on the top!");
			if (Current is OpaqueExpressionNode)
			{
				Current = Current.Parent.Parent;
			}
			else
			{
				Current = Current.Parent;
			}
		}

		/// <summary>
		/// Generates the expression.
		/// </summary>
		/// <returns>Whole tree expression.</returns>
		public Expression GenerateExpression()
		{
			return Root.GetExpression(this);
		}

		/// <summary>
		/// Finds the nearest closing bracket and set current.
		/// </summary>
		/// <returns><c>True</c> if succesed to find nearest closing bracket; otherwise <c>false</c>.</returns>
		public bool FindNearestClosingBracketAndSetCurrent()
		{
			BuilderTreeNodeBase currentNode = Current;
			while (currentNode.Parent != null)
			{
				currentNode = currentNode.Parent;
				if ((currentNode is BracketNode) || (currentNode is FunctionOrPropertyNode) || (currentNode is NewInstanceNode) || (currentNode is NotNode))
				{
					Current = currentNode;
					return true;
				}
			}
			return false;
		}
		/// <summary>
		/// Finds the nearest closing index bracket and set current.
		/// </summary>
		/// <returns><c>True</c> if succesed to find nearest closing index bracket; otherwise <c>false</c>.</returns>
		public bool FindNearestClosingIndexBracketAndSetCurrent()
		{
			BuilderTreeNodeBase currentNode = Current;
			while (currentNode.Parent != null)
			{
				currentNode = currentNode.Parent;
				if (currentNode is IndexerNode)
				{
					Current = currentNode;
					return true;
				}
			}
			return false;
		}
	}
}
